前提
需要先依据react官网教程编写出基础的井字格游戏。
拓展实现及说明
最后面会有全部的源代码。
1、在游戏历史记录列表显示每一步棋的坐标,格式为 (列号, 行号)
直接给history里的squres再添加一列,保存点击的i值,即第几个方格,再在moves里计算得出列号和行号。 ![加下标](https://img-blog.csdnimg.cn/7c0166a50fd14427a30631c1ee88c491.png)
ps: Math.trunc()方法是通过除去小数位来返回浮点数的整数部分
2、在历史记录列表中加粗显示当前选择的项目
给历史记录列表的按钮绑定一个动态样式即可。 ![加粗当前选择的记录](https://img-blog.csdnimg.cn/d7e23a0a9f3b483580e03040048a5e0f.png)
3、使用两个循环来渲染出棋盘的格子,而不是在代码里写死(hardcode)
![双重for循环](https://img-blog.csdnimg.cn/95f448614d15477b90a9e51da88a36ec.png)
4、添加一个可以升序或降序显示历史记录的按钮
定义一个排序标志,升序为true,降序false。然后通过这个标志来升序或降序显示history数组的内容即可。 ![降序或升序](https://img-blog.csdnimg.cn/1ad1da7ad9f5417f89c36a90921babfd.png)
5、每当有人获胜时,高亮显示连成一线的 3 颗棋子
需要修改原来的计算成功者的方法calculateWinner,返回连成一线的下标数组winnerList,board组件双重循环渲染squre组件时可根据这个winnerList传一个flag标志给squre组件,然后squre组件里如果这个flag标志为true就背景色改变,就OK了。 board组件里修改的内容,注意第一行一定要取返回值得第一项,否则会出现点击没反应的情况。 最后,square组件根据lightFlag标志,动态显示背景颜色就大功告成了! ![square组件修改](https://img-blog.csdnimg.cn/9654fe0538884c6f82b9097dc86976bb.png)
6、当无人获胜时,显示一个平局的消息
判断当前的square是否填满,如果填满了,且未胜利即平局。 ![增加平局描述](https://img-blog.csdnimg.cn/95ce2e7345b24321b768302250181774.png)
源码和最终成果截图
完整源码
import {useState} from 'react';
function Square({value,lightFlag, onSquareClick}) {
return (
backgroundColor: lightFlag ? 'green' : 'transparent'}}
className="square"
onClick={onSquareClick}>
{value}
);
}
function Board({xIsNext, squares, onPlay}) {
function handleClick(i) {
if (calculateWinner(squares)[0] || squares[i]) {
return;
}
const nextSquares = squares.slice();
if (xIsNext) {
nextSquares[i] = 'X';
} else {
nextSquares[i] = 'O';
}
nextSquares[9] = i //增加一列记录下标,可通过计算转坐标
onPlay(nextSquares);
}
const [winner,winnerLine] = calculateWinner(squares);
let status;
if (winner) {
status = '获胜的是: ' + winner;
} else {
if(!squares.includes(null)){
status='实力伯仲之间,平局'
}else {
status = '下一步棋手: ' + (xIsNext ? 'X' : 'O');
}
}
const numbers = [0, 1, 2]
const listItems = numbers.map((number, rowIndex) => {
return (
numbers.map((item, columnIndex) => {
let lightFlag=winnerLine.includes(rowIndex * 3 + columnIndex)
return renderSquare(rowIndex * 3 + columnIndex,lightFlag)
})
}
)
})
//生成方格
function renderSquare(i,lightFlag) {
return (
squares[i]}
lightFlag={lightFlag}
onSquareClick={() => handleClick(i)}/>
);
}
return (
{status}
{listItems}
{/**/}
{/* handleClick(0)} />*/}
{/* handleClick(1)} />*/}
{/* handleClick(2)} />*/}
{/**/}
{/**/}
{/* handleClick(3)} />*/}
{/* handleClick(4)} />*/}
{/* handleClick(5)} />*/}
{/**/}
{/**/}
{/* handleClick(6)} />*/}
{/* handleClick(7)} />*/}
{/* handleClick(8)} />*/}
{/**/}
);
}
export default function Game() {
const [history, setHistory] = useState([Array(10).fill(null)]);
const [currentMove, setCurrentMove] = useState(0);
const [sortReverseFlag,setSortReverseFlag]=useState(true); //排序标志
const xIsNext = currentMove % 2 === 0;
const currentSquares = history[currentMove];
function handlePlay(nextSquares) {
const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
setHistory(nextHistory);
setCurrentMove(nextHistory.length - 1);
}
function jumpTo(nextMove) {
setCurrentMove(nextMove);
}
const moves = history.map((squares, move) => {
let description;
move=sortReverseFlag?move:history.length-move-1
if (move > 0) {
description = '跳到第' + move + '步,坐标('
+ Math.trunc(squares[9] / 3 + 1) + ',' + (squares[9] % 3 + 1) + ')'
+",下棋者:"+ (move%2 ?'X':'O');
} else {
description = '重新开始游戏';
}
return (
{fontWeight: (move === currentMove) ? 'bold' : 'normal'}}
onClick={() => jumpTo(move)}>
{description}
);
});
return (
currentSquares} onPlay={handlePlay}/>
sortReverseFlag ? '升序' : '降序'}
{moves}
);
}
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i
return [squares[a],lines[i]];
}
}
return [null,[]];
}
最终成果截图
获胜截图: 倒序截图: ![历史记录倒序](https://img-blog.csdnimg.cn/790e1803107f454ba3d87d44d6bdf0d1.png)
|